//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package docker_dao

import (
	"context"
	"regexp"

	"atomgit.com/openlinksaas/api-server/dao/db_ns"
	"atomgit.com/openlinksaas/proto-gen-go.git/docker_template_api"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type AppInfoDbItem struct {
	AppId         string `bson:"_id" json:"_id"`
	Name          string `bson:"name" json:"name"`
	Desc          string `bson:"desc" json:"desc"`
	IconFileId    string `bson:"iconFileId" json:"iconFileId"`
	CateId        string `bson:"cateId" json:"cateId"`
	OfficialUrl   string `bson:"officialUrl" json:"officialUrl"`
	DocUrl        string `bson:"docUrl" json:"docUrl"`
	TemplateCount uint32 `bson:"templateCount" json:"templateCount"`
	CreateTime    int64  `bson:"createTime" json:"createTime"`
	UpdateTime    int64  `bson:"updateTime" json:"updateTime"`
	//后续功能预留
	BadCount  uint32 `bson:"badCount" json:"badCount"`
	GoodCount uint32 `bson:"goodCount" json:"goodCount"`
}

func (item *AppInfoDbItem) ToAppInfo() *docker_template_api.AppInfo {
	return &docker_template_api.AppInfo{
		AppId:         item.AppId,
		Name:          item.Name,
		Desc:          item.Desc,
		IconFileId:    item.IconFileId,
		CateId:        item.CateId,
		TemplateCount: item.TemplateCount,
		OfficialUrl:   item.OfficialUrl,
		DocUrl:        item.DocUrl,
		CreateTime:    item.CreateTime,
		UpdateTime:    item.UpdateTime,
	}
}

type _AppDao struct {
	mc *mongo.Collection
}

func newAppDao(db *mongo.Database) (*_AppDao, error) {
	mc := db.Collection(db_ns.DB_NS_DOCKER + "app")
	_, err := mc.Indexes().CreateMany(context.Background(), []mongo.IndexModel{
		{
			Keys: bson.D{{"cateId", 1}, {"updateTime", -1}},
		},
		{
			Keys: bson.D{{"cateId", 1}, {"goodCount", 1}, {"updateTime", -1}},
		},
	})
	if err != nil {
		return nil, err
	}
	return &_AppDao{mc: mc}, nil
}

func (db *_AppDao) Insert(ctx context.Context, dbItem *AppInfoDbItem) error {
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_AppDao) Count(ctx context.Context, filterByCateId bool, cateId string, filterByKeyword bool, keyword string) (uint32, error) {
	query := bson.M{}
	if filterByCateId {
		query["cateId"] = cateId
	}
	if filterByKeyword {
		query["name"] = primitive.Regex{
			Pattern: regexp.QuoteMeta(keyword),
			Options: "i",
		}
	}
	count, err := db.mc.CountDocuments(ctx, query)
	return uint32(count), err
}

func (db *_AppDao) List(ctx context.Context, filterByCateId bool, cateId string, filterByKeyword bool, keyword string, offset, limit int64) ([]*AppInfoDbItem, error) {
	query := bson.M{}
	if filterByCateId {
		query["cateId"] = cateId
	}
	if filterByKeyword {
		query["name"] = primitive.Regex{
			Pattern: regexp.QuoteMeta(keyword),
			Options: "i",
		}
	}
	cursor, err := db.mc.Find(ctx, query, options.Find().SetSkip(offset).SetLimit(limit).SetSort(bson.M{"updateTime": -1}))
	if err != nil {
		return nil, err
	}
	retList := []*AppInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_AppDao) ListAll(ctx context.Context) ([]*AppInfoDbItem, error) {
	cursor, err := db.mc.Find(ctx, bson.M{}, options.Find().SetSort(bson.M{"updateTime": -1}))
	if err != nil {
		return nil, err
	}
	retList := []*AppInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_AppDao) Exist(ctx context.Context, appId string) (bool, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"_id": appId})
	return count > 0, err
}

func (db *_AppDao) Get(ctx context.Context, appId string) (*AppInfoDbItem, error) {
	retItem := &AppInfoDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"_id": appId}).Decode(retItem)
	return retItem, err
}

func (db *_AppDao) Remove(ctx context.Context, appId string) error {
	_, err := db.mc.DeleteOne(ctx, bson.M{"_id": appId})
	return err
}

func (db *_AppDao) Update(ctx context.Context, appId, name, desc, iconFileId, cateId, officialUrl, docUrl string, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": appId}, bson.M{"$set": bson.M{
		"name":        name,
		"desc":        desc,
		"iconFileId":  iconFileId,
		"cateId":      cateId,
		"officialUrl": officialUrl,
		"docUrl":      docUrl,
		"updateTime":  updateTime,
	}})
	return err
}

func (db *_AppDao) UpdateTemplateCount(ctx context.Context, appId string, count uint32) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": appId}, bson.M{"$set": bson.M{"templateCount": count}})
	return err
}
